/*
 * Copyright (c) 2021, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.alg.filter.convolve.normalized;

import boofcv.struct.border.ImageBorder_F32;
import boofcv.struct.border.ImageBorder_F64;
import boofcv.struct.border.ImageBorder_S32;
import boofcv.struct.convolve.*;
import boofcv.struct.image.*;

import javax.annotation.Generated;

/**
 * <p>
 * Convolution with kernel renormalization around image borders. Unoptimized naive implementation.
 * </p>
 * 
 * <p>
 * NOTE: Do not modify. Automatically generated by GenerateConvolveNormalizedNaive_SB.
 * </p>
 * @author Peter Abeles
 */
@Generated({"boofcv.alg.filter.convolve.normalized.GenerateConvolveNormalizedNaive_SB"})
public class ConvolveNormalizedNaive_SB {

	public static void horizontal(Kernel1D_F32 kernel, GrayF32 input, GrayF32 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				float total = 0;
				float weight = 0;

				int startX = x - offset;
				int endX = startX+kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				for( int j = startX; j < endX; j++ ) {
					float v = kernel.get(j-x+offset);
					total += input.get(j,y)*v;
					weight += v;
				}
				output.set(x,y, total/weight );
			}
		}
	}

	public static void vertical(Kernel1D_F32 kernel, GrayF32 input, GrayF32 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				float total = 0;
				float weight = 0;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				for( int i = startY; i < endY; i++ ) {
					float v = kernel.get(i-y+offset);
					total += input.get(x,i)*v;
					weight += v;
				}
				output.set(x,y, total/weight );
			}
		}
	}

	public static void convolve(Kernel2D_F32 kernel, GrayF32 input, GrayF32 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {

				int startX = x - offset;
				int endX = startX + kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				float total = 0;
				float weight = 0;

				for( int i = startY; i < endY; i++ ) {
					for( int j = startX; j < endX; j++ ) {
						float v = kernel.get(j-x+offset,i-y+offset);
						total += input.get(j,i)*v;
						weight += v;
					}
				}
				output.set(x,y, total/weight );
			}
		}
	}

	public static void horizontal(Kernel1D_F32 kernel, GrayF32 input, GrayF32 output, ImageBorder_F32 binput ) {

		binput.setImage(input);
		final int offset = kernel.getOffset();
		final float weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				float total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int xx = x - offset + j;
					float v = kernel.get(j);
					total += binput.get(xx,y)*v;
				}
				output.set(x,y, total/weight);
			}
		}
	}

	public static void vertical(Kernel1D_F32 kernel, GrayF32 input, GrayF32 output, ImageBorder_F32 binput ) {
		final int offset = kernel.getOffset();
		final float weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				float total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int yy = y - offset + j;
					float v = kernel.get(j);
					total += binput.get(x,yy)*v;
				}
				output.set(x,y, total/weight);
			}
		}
	}

	public static void convolve(Kernel2D_F32 kernel, GrayF32 input, GrayF32 output, ImageBorder_F32 binput ) {
		final int offset = kernel.getOffset();
		final float weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				float total = 0;

				for( int i = 0; i < kernel.getWidth(); i++ ) {
					int yy = y - offset + i; 
					for( int j = 0; j < kernel.getWidth(); j++ ) {
						int xx = x - offset + j;
						float v = kernel.get(j,i);
						total += binput.get(xx,yy)*v;
					}
				}
				output.set(x,y, total/weight);
			}
		}
	}

	public static void horizontal(Kernel1D_F64 kernel, GrayF64 input, GrayF64 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				double total = 0;
				double weight = 0;

				int startX = x - offset;
				int endX = startX+kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				for( int j = startX; j < endX; j++ ) {
					double v = kernel.get(j-x+offset);
					total += input.get(j,y)*v;
					weight += v;
				}
				output.set(x,y, total/weight );
			}
		}
	}

	public static void vertical(Kernel1D_F64 kernel, GrayF64 input, GrayF64 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				double total = 0;
				double weight = 0;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				for( int i = startY; i < endY; i++ ) {
					double v = kernel.get(i-y+offset);
					total += input.get(x,i)*v;
					weight += v;
				}
				output.set(x,y, total/weight );
			}
		}
	}

	public static void convolve(Kernel2D_F64 kernel, GrayF64 input, GrayF64 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {

				int startX = x - offset;
				int endX = startX + kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				double total = 0;
				double weight = 0;

				for( int i = startY; i < endY; i++ ) {
					for( int j = startX; j < endX; j++ ) {
						double v = kernel.get(j-x+offset,i-y+offset);
						total += input.get(j,i)*v;
						weight += v;
					}
				}
				output.set(x,y, total/weight );
			}
		}
	}

	public static void horizontal(Kernel1D_F64 kernel, GrayF64 input, GrayF64 output, ImageBorder_F64 binput ) {

		binput.setImage(input);
		final int offset = kernel.getOffset();
		final double weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				double total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int xx = x - offset + j;
					double v = kernel.get(j);
					total += binput.get(xx,y)*v;
				}
				output.set(x,y, total/weight);
			}
		}
	}

	public static void vertical(Kernel1D_F64 kernel, GrayF64 input, GrayF64 output, ImageBorder_F64 binput ) {
		final int offset = kernel.getOffset();
		final double weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				double total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int yy = y - offset + j;
					double v = kernel.get(j);
					total += binput.get(x,yy)*v;
				}
				output.set(x,y, total/weight);
			}
		}
	}

	public static void convolve(Kernel2D_F64 kernel, GrayF64 input, GrayF64 output, ImageBorder_F64 binput ) {
		final int offset = kernel.getOffset();
		final double weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				double total = 0;

				for( int i = 0; i < kernel.getWidth(); i++ ) {
					int yy = y - offset + i; 
					for( int j = 0; j < kernel.getWidth(); j++ ) {
						int xx = x - offset + j;
						double v = kernel.get(j,i);
						total += binput.get(xx,yy)*v;
					}
				}
				output.set(x,y, total/weight);
			}
		}
	}

	public static void horizontal(Kernel1D_S32 kernel, GrayU8 input, GrayI8 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;
				int weight = 0;

				int startX = x - offset;
				int endX = startX+kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				for( int j = startX; j < endX; j++ ) {
					int v = kernel.get(j-x+offset);
					total += input.get(j,y)*v;
					weight += v;
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernel, GrayU8 input, GrayI8 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;
				int weight = 0;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				for( int i = startY; i < endY; i++ ) {
					int v = kernel.get(i-y+offset);
					total += input.get(x,i)*v;
					weight += v;
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void convolve(Kernel2D_S32 kernel, GrayU8 input, GrayI8 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {

				int startX = x - offset;
				int endX = startX + kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				int total = 0;
				int weight = 0;

				for( int i = startY; i < endY; i++ ) {
					for( int j = startX; j < endX; j++ ) {
						int v = kernel.get(j-x+offset,i-y+offset);
						total += input.get(j,i)*v;
						weight += v;
					}
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void horizontal(Kernel1D_S32 kernel, GrayU8 input, GrayI8 output, ImageBorder_S32<GrayU8> binput ) {

		binput.setImage(input);
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int xx = x - offset + j;
					int v = kernel.get(j);
					total += binput.get(xx,y)*v;
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernel, GrayU8 input, GrayI8 output, ImageBorder_S32<GrayU8> binput ) {
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int yy = y - offset + j;
					int v = kernel.get(j);
					total += binput.get(x,yy)*v;
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void convolve(Kernel2D_S32 kernel, GrayU8 input, GrayI8 output, ImageBorder_S32<GrayU8> binput ) {
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int i = 0; i < kernel.getWidth(); i++ ) {
					int yy = y - offset + i; 
					for( int j = 0; j < kernel.getWidth(); j++ ) {
						int xx = x - offset + j;
						int v = kernel.get(j,i);
						total += binput.get(xx,yy)*v;
					}
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void horizontal(Kernel1D_S32 kernel, GrayS16 input, GrayI16 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;
				int weight = 0;

				int startX = x - offset;
				int endX = startX+kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				for( int j = startX; j < endX; j++ ) {
					int v = kernel.get(j-x+offset);
					total += input.get(j,y)*v;
					weight += v;
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernel, GrayS16 input, GrayI16 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;
				int weight = 0;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				for( int i = startY; i < endY; i++ ) {
					int v = kernel.get(i-y+offset);
					total += input.get(x,i)*v;
					weight += v;
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void convolve(Kernel2D_S32 kernel, GrayS16 input, GrayI16 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {

				int startX = x - offset;
				int endX = startX + kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				int total = 0;
				int weight = 0;

				for( int i = startY; i < endY; i++ ) {
					for( int j = startX; j < endX; j++ ) {
						int v = kernel.get(j-x+offset,i-y+offset);
						total += input.get(j,i)*v;
						weight += v;
					}
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void horizontal(Kernel1D_S32 kernel, GrayS16 input, GrayI16 output, ImageBorder_S32<GrayS16> binput ) {

		binput.setImage(input);
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int xx = x - offset + j;
					int v = kernel.get(j);
					total += binput.get(xx,y)*v;
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernel, GrayS16 input, GrayI16 output, ImageBorder_S32<GrayS16> binput ) {
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int yy = y - offset + j;
					int v = kernel.get(j);
					total += binput.get(x,yy)*v;
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void convolve(Kernel2D_S32 kernel, GrayS16 input, GrayI16 output, ImageBorder_S32<GrayS16> binput ) {
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int i = 0; i < kernel.getWidth(); i++ ) {
					int yy = y - offset + i; 
					for( int j = 0; j < kernel.getWidth(); j++ ) {
						int xx = x - offset + j;
						int v = kernel.get(j,i);
						total += binput.get(xx,yy)*v;
					}
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void horizontal(Kernel1D_S32 kernel, GrayU16 input, GrayI16 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;
				int weight = 0;

				int startX = x - offset;
				int endX = startX+kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				for( int j = startX; j < endX; j++ ) {
					int v = kernel.get(j-x+offset);
					total += input.get(j,y)*v;
					weight += v;
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernel, GrayU16 input, GrayI16 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;
				int weight = 0;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				for( int i = startY; i < endY; i++ ) {
					int v = kernel.get(i-y+offset);
					total += input.get(x,i)*v;
					weight += v;
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void convolve(Kernel2D_S32 kernel, GrayU16 input, GrayI16 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {

				int startX = x - offset;
				int endX = startX + kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				int total = 0;
				int weight = 0;

				for( int i = startY; i < endY; i++ ) {
					for( int j = startX; j < endX; j++ ) {
						int v = kernel.get(j-x+offset,i-y+offset);
						total += input.get(j,i)*v;
						weight += v;
					}
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void horizontal(Kernel1D_S32 kernel, GrayU16 input, GrayI16 output, ImageBorder_S32<GrayU16> binput ) {

		binput.setImage(input);
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int xx = x - offset + j;
					int v = kernel.get(j);
					total += binput.get(xx,y)*v;
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernel, GrayU16 input, GrayI16 output, ImageBorder_S32<GrayU16> binput ) {
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int yy = y - offset + j;
					int v = kernel.get(j);
					total += binput.get(x,yy)*v;
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void convolve(Kernel2D_S32 kernel, GrayU16 input, GrayI16 output, ImageBorder_S32<GrayU16> binput ) {
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int i = 0; i < kernel.getWidth(); i++ ) {
					int yy = y - offset + i; 
					for( int j = 0; j < kernel.getWidth(); j++ ) {
						int xx = x - offset + j;
						int v = kernel.get(j,i);
						total += binput.get(xx,yy)*v;
					}
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void horizontal(Kernel1D_S32 kernel, GrayS32 input, GrayS32 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;
				int weight = 0;

				int startX = x - offset;
				int endX = startX+kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				for( int j = startX; j < endX; j++ ) {
					int v = kernel.get(j-x+offset);
					total += input.get(j,y)*v;
					weight += v;
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernel, GrayS32 input, GrayS32 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;
				int weight = 0;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				for( int i = startY; i < endY; i++ ) {
					int v = kernel.get(i-y+offset);
					total += input.get(x,i)*v;
					weight += v;
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void convolve(Kernel2D_S32 kernel, GrayS32 input, GrayS32 output ) {

		final int offset = kernel.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {

				int startX = x - offset;
				int endX = startX + kernel.getWidth();

				if( startX < 0 ) startX = 0;
				if( endX > width ) endX = width;

				int startY = y - offset;
				int endY = startY + kernel.getWidth();

				if( startY < 0 ) startY = 0;
				if( endY > height ) endY = height;

				int total = 0;
				int weight = 0;

				for( int i = startY; i < endY; i++ ) {
					for( int j = startX; j < endX; j++ ) {
						int v = kernel.get(j-x+offset,i-y+offset);
						total += input.get(j,i)*v;
						weight += v;
					}
				}
				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void horizontal(Kernel1D_S32 kernel, GrayS32 input, GrayS32 output, ImageBorder_S32<GrayS32> binput ) {

		binput.setImage(input);
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int xx = x - offset + j;
					total += binput.get(xx,y)*kernel.get(j);
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernel, GrayS32 input, GrayS32 output, ImageBorder_S32<GrayS32> binput ) {
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int j = 0; j < kernel.getWidth(); j++ ) {
					int yy = y - offset + j;
					int v = kernel.get(j);
					total += binput.get(x,yy)*v;
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void convolve(Kernel2D_S32 kernel, GrayS32 input, GrayS32 output, ImageBorder_S32<GrayS32> binput ) {
		final int offset = kernel.getOffset();
		final int weight = kernel.computeSum();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for( int x = 0; x < width; x++ ) {
				int total = 0;

				for( int i = 0; i < kernel.getWidth(); i++ ) {
					int yy = y - offset + i; 
					for( int j = 0; j < kernel.getWidth(); j++ ) {
						int xx = x - offset + j;
						int v = kernel.get(j,i);
						total += binput.get(xx,yy)*v;
					}
				}
				output.set(x,y, (total+weight/2)/weight);
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernelX, Kernel1D_S32 kernelY,
							GrayU16 input, GrayI8 output ) {

		final int offsetX = kernelX.getOffset();
		final int offsetY = kernelY.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				int total = 0;
				int weightY = 0;

				int startY = y - offsetY;
				int endY = startY + kernelY.getWidth();

				if (startY < 0) startY = 0;
				if (endY > height) endY = height;

				for (int i = startY; i < endY; i++) {
					int v = kernelY.get(i - y + offsetY);
					total += input.get(x, i) * v;
					weightY += v;
				}

				int kerX0 = Math.max(0, offsetX - x);
				int kerX1 = Math.min(kernelX.getWidth(), width - x + offsetX);

				int weightX = 0;
				for (int i = kerX0; i < kerX1; i++) {
					weightX += kernelX.get(i);
				}

				int weight = weightX * weightY;

				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

	public static void vertical(Kernel1D_S32 kernelX, Kernel1D_S32 kernelY,
							GrayS32 input, GrayI16 output ) {

		final int offsetX = kernelX.getOffset();
		final int offsetY = kernelY.getOffset();

		final int width = input.getWidth();
		final int height = input.getHeight();

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				int total = 0;
				int weightY = 0;

				int startY = y - offsetY;
				int endY = startY + kernelY.getWidth();

				if (startY < 0) startY = 0;
				if (endY > height) endY = height;

				for (int i = startY; i < endY; i++) {
					int v = kernelY.get(i - y + offsetY);
					total += input.get(x, i) * v;
					weightY += v;
				}

				int kerX0 = Math.max(0, offsetX - x);
				int kerX1 = Math.min(kernelX.getWidth(), width - x + offsetX);

				int weightX = 0;
				for (int i = kerX0; i < kerX1; i++) {
					weightX += kernelX.get(i);
				}

				int weight = weightX * weightY;

				output.set(x,y, (total+weight/2)/weight );
			}
		}
	}

}
